home *** CD-ROM | disk | FTP | other *** search
- page 60,132
- title MEMTEST - Software Technique's Memory Test
- ;
- ; MEMTEST - A fast parity check for all memory on option cards
- ;
- ; Copyright, 1983, Software Technique, Inc. Permission is
- ; granted to copy and distribute, provided this copyright
- ; notice remains on all copies made.
- ;
- ; This program tests Planar (lower 64K) or add-on memory by performing
- ; initialization and fast successive reads, reporting any errors it
- ; finds. If the program is loaded in low memory (LINK memtest;), it
- ; will test the add-on memory. If it is loaded into high memory (LINK
- ; memtest/h;), it will test the lower 64K bytes, with the exclusion of
- ; the first 0600H bytes of RAM. This program is fast; it does
- ; not perform the (probably) more exhaustive tests of IBM's Advanced
- ; diagnostics, but it is materially faster. It is especially useful
- ; for finding the intermittent kinds of errors that seem to crop up
- ; only after several hours. The principle is simple: We write all of
- ; memory with a consistent pattern, and then we sweep through and read
- ; it again and again. We capture all Non-maskable Interrupts so you
- ; won't see the "PARITY CHECK 2" or "PARITY CHECK 1" messages.
- ;
- ; The display shows the current status of testing, and up to 22 found
- ; errors. After 22 errors, the program waits for manual intervention
- ; so you can let it run overnight and the errors will be displayed on
- ; the screen when you return. Use Shift-PrtSc to print out the error
- ; messages.
- ;
- ; An "odometer" is maintained on the screen that displays the number
- ; of read cycles since the last time memory was "primed" with the
- ; known pattern. The "odometer" is named the "Cycle count." When the
- ; count is blank, the program is initializing memory. The counter is
- ; incremented at the start of each read sweep.
- ;
- ; Errors are discriminated into three types:
- ; Parity Error (that is, NMI struck & bits are bad)
- ; Spurious NMI Error (that is, NMI struck, but no bad bits)
- ; Mismatch Error (that is, no parity error, but the bits
- ; weren't what we expected)
- ; The error message reports in the following format:
- ; SSSS:OOOO=BB(XX/YY) where
- ; SSSS = Segment (always N000 or N800)
- ; OOOO = Offset (always < 8000)
- ; BB = One's in places where bits are bad
- ; XX = Pattern read from memory in error
- ; YY = Second pattern read from memory after
- ; error detected
- ; We take care to make sure that we reread reportedly faulty bit
- ; places several times; this assures us some coverage of the "floating
- ; output" problem for missing chips or memory devices that won't
- ; enable their outputs. We check for pattern mismatch because parity
- ; checks only detect odd numbers of bits in error (two or four bits in
- ; error in a byte won't be caught by parity).
- ;
- ; After an error is reported, testing resumes from the next 32K byte
- ; bank. After the end of memory has been reached, it will be re-
- ; initialized and the "Cycle" count will be reset to zero. If two
- ; or more errors are found during a sweep, the second and successive
- ; error lines will not have the "Cycle" counter displayed.
- ;
- ; Please report problems to Carol Anne Ogdin at 703/549-0646
- ;
- ;
- PORTB equ 61H
- PORTC equ 62H
- KBDIN equ 60H
- VIDEO macro
- mov ah,0EH ;Write as if to TTY
- int 10H
- endm
- DISPLAY macro TXT
- mov si,offset TXT
- call TTYOUT
- endm
- ;
- TEST segment
- assume cs:TEST,es:TEST
- db 'Copr. 1983 Software Technique, Inc. V1.0'
- CYCLES dw 0 ;Number of passes made
- MINI db 0 ;Number of lines displayed so far
- MAX equ 22 ;Maximum number of displayed lines permitted
- FLAG db 0 ;Non-zero if NMI
- SAVE db 0 ;Faulty bits during write/read test
- FIRST db 0 ;First-read faulty byte
- SECOND db 0 ;Second-read faulty byte
- FOUND db 0 ;Found-an-error this pass
- TABLE db '0123456789ABCDEF';Hex conversion
- MSG1A db ' Parity',0
- MSG1B db ' Spurious NMI',0
- MSG1C db ' Mismatch',0
- MSG7 db ' Error at ',0
- MSG2 db 'Cycle: ',0
- MSG2A db ' ',0
- MSG3 db 4 dup (08H),0 ;Backspace over prior cycle number
- MSG6 db 0DH,0AH,'Software Technique, Inc. '
- MSG6A db 'Add-on RAM Test'
- db 0DH,0AH,'Hit any key to stop, Alt-Ctrl-Del to end'
- MSG4 db 0DH,0AH,0 ;Carriage Return, Line Feed (new line)
- MSG5 db 'Hit any key to resume testing.',0
- MSG8 db 'Planar'
- ;
- ; Main entry point
- ;
- INIT: mov FOUND,-1 ;Mark memory as needing a refresh
- mov ax,cs ;Figure out which bank we're in
- mov ds,ax ;Make (ds)=(es)=(cs)
- mov es,ax
- test ah,0F0H
- jz RECYCLE
- mov cx,6 ;Change message form
- mov di,offset MSG6A
- mov si,offset MSG8
- rep movsb
- RECYCLE:call CLEAR
- ;
- ; Initialize for the next sweep
- ;
- REFRESH:cmp FOUND,0 ;Any reason to refresh the memory?
- je PRESET
- call SETALL ;Prime the memory (and clear FOUND)
- PRESET: mov ax,cs ; Make (ds)=(cs) again
- mov ds,ax
- ;
- ; This program shows the number of memory read cycles on the current
- ; Video Display line. When an error occurs, it shows the segment,
- ; offset and the bit(s) in error (as 1's in a field of zeros). The
- ; program displays successive errors on successive lines of the display
- ; and waits for operator specification before erasing the display.
- ;
- START: mov bh,0
- cmp FOUND,0 ;If any error found
- jne NEXT ; then end the pass
- mov ah,1 ;Check for keyboard action
- int 16H
- jnz STOP ;Stop reading
- DISPLAY MSG3 ;Back up over prior cycle number display
- inc CYCLES ;Increment cycle count
- jz NEXT ;Start a new line after 64K tries!
- mov ax,CYCLES ;Show cycles run in Hex
- call HEXOUT
- ;
- call GETSIZE ;Find memory size to read (set cx)
- RESUME: call READALL ;Check for errors
- mov dx,ds ;save DS
- mov ax,cs ; and restore old DS
- mov ds,ax
- jo START ;Finished this pass
- ; Error found. dx:bx=address of error, SAVE=faulty bits
- push dx ;Save segment for resumption later
- push cx ; and the remaining bank count
- mov cx,bx ;Save the offset in bank
- mov bh,0 ;Set for Screen 0
- cmp FOUND,0 ;See if this is second message
- jz SKIP ;No. first time, skip this
- DISPLAY MSG2A ;Align error messages
- SKIP: call ERROR ;Go show error message
- pop cx ;Restore remaining bank count
- dec cx ; and account for this one done
- pop dx ;Reclaim bank segment number
- add dx,800H ; and advance to next
- mov FOUND,0FFH ;Mark the cycle as having an error
- jmp RESUME ;Resume reading for errors
- ;
- STOP: mov MINI,1 ;Force screen-full halt
- NEXT: DISPLAY MSG4 ;Start a new line on display
- mov CYCLES,0 ;Reset read-cycle count
- dec MINI ;Screen full yet?
- jz FULL ; Yes.
- DISPLAY MSG2 ;Show next line's Cycle message
- jmp REFRESH
- FULL: DISPLAY MSG5 ;Ask for permission to go on
- FLUSH: mov ah,1 ;Flush out any waiting characters
- int 16H
- jz WAIT
- mov ah,0 ;Get the waiting character
- int 16H
- jmp FLUSH
- WAIT: mov ah,1 ;Wait for a keystroke
- int 16H
- jz WAIT
- mov ah,0
- int 16H
- jmp RECYCLE
- ;
- ; Issue the error message and supporting information
- ; at entry, (dx)=segment address, (cx)=offset, (bh)=0
- ;
- ERROR: mov si,offset MSG1C
- cmp FLAG,0
- jz ISSUE ;No NMI. Must've been mismatch
- mov si,offset MSG1B
- cmp SAVE,0
- jz ISSUE ;No bits in error; Spurious NMI?
- mov si,offset MSG1A ;Must've been Parity error
- ISSUE: call TTYOUT
- DISPLAY MSG7
- mov ax,dx ;Show segment address
- call HEXOUT
- mov al,':'
- VIDEO
- mov ax,cx ;Reclaim offset
- call HEXOUT
- mov al,'='
- VIDEO
- mov al,SAVE ;Show error bit locations
- call BYTOUT
- mov al,'('
- VIDEO
- mov al,FIRST ;Show first byte read
- call BYTOUT
- mov al,'/'
- VIDEO
- mov al,SECOND ; and then second
- call BYTOUT
- mov al,')'
- VIDEO
- ret
- ;
- HEXOUT: push ax ;Save low-order digit
- mov al,ah ;Convert high digit first
- call BYTOUT ;Issue one byte
- pop ax ;Reclaim second byte
- BYTOUT: push ax ;Save digit
- shr al,1 ;Put high-order digit in low-order bits
- shr al,1
- shr al,1
- shr al,1
- call DIGOUT ;Issue first digit
- pop ax ;Get second digit back
- DIGOUT: and al,0FH ;isolate four bits
- mov bx,offset TABLE ;Setup to translate hex
- xlat
- mov bh,0 ;Restore for video
- VIDEO
- ret
- ;
- ; Prime a 32K byte bank
- ; ds: Base address of the bank
- ;
- PRIME: mov ds,dx ;Set for this 32K page
- PRIME1: mov byte ptr [bx],bl;Store count in next location
- inc bx
- jno PRIME1 ;Continue until 8000H
- SETXIT: ret
- ;
- ; Prime all of available memory
- ;
- SETALL: call GETSIZE ;How much memory to set?
- mov FOUND,0 ;Reset error-in-memory flag
- SETNEXT:jcxz SETXIT
- mov ds,dx
- call PRIME ;Prime next bank
- add dx,800H ;Advance segment by 32K
- mov bx,0
- dec cx
- jmp SETNEXT
- ;
- ; Read all of a 32K bank, looking for an error
- ;
- READ: mov ds,dx
- READ1: mov al,[bx] ;This reads a byte; NMI if parity error
- test FLAG,0FFH ; If there was an error,
- jnz READERR ; this will jump 'cause FLAG<>0
- cmp al,bl ;This catches even # of bit errors
- jnz READERR
- inc bx
- jno READ1 ;Do until bx=8000H
- ret
- READERR:mov FIRST,al ;Save the byte, as read
- mov al,[bx] ;and try reading it again
- mov SECOND,al
- mov al,0 ;Assume no bits in error
- mov bh,10 ;Try these tests because of floats
- NEXTRY: mov byte ptr [bx],0
- or al,[bx] ;Get some perhaps bad bits
- mov byte ptr [bx],0FFH ;Try the complement
- mov ah,[bx]
- xor ah,0FFH ;Complement the result
- or al,ah ;Put bad bits together
- dec bh
- jnz NEXTRY
- mov SAVE,al
- ret ;Note: OF is clear (by 'or')
- ;
- ; Read all add-on memory, using READ for each 32K byte bank
- ; At entry, (cx) = # of 32K banks yet to scan
- ; (dx) = segment address of next bank to scan
- ;
- READALL:mov FLAG,0 ;Clear markers
- mov SAVE,0
- call GETSIZE ;Set up (dx), (bx) and (cx)
- ;Save the existing NMI interrupt routine vector and set our own
- xor ax,ax
- mov es,ax
- mov ax,es:8
- push ax ;Save IP
- mov ax,es:10
- push ax ;Save CS
- mov word ptr es:8,offset NMISVC
- mov word ptr es:10,cs ;Use this segment
- RDNEXT: jcxz RDEXIT
- call READ ;And cycle through it
- jno RDERR ;Oops. Found an error, so quit
- mov bx,0
- add dx,800H
- dec cx
- jmp RDNEXT
- RDEXIT: mov al,07FH
- rol al,1 ;Set OF to mark no error
- RDERR: pop ax ;Get back saves CS:IP for 10:8
- mov word ptr es:10,ax
- pop ax
- mov word ptr es:8, ax
- ret
- ; Find the size of the memory we're about to read or write
- GETSIZE:mov ax,cs ;Am I in Low or High memory?
- test ah,0F0H ;See if we're above first 64K
- jz HITEST ;I'm in low memory, so test HIGH
- mov bx,600H ;Skip first 600H bytes for BIOS
- mov dx,0
- mov cx,2 ;Only do two banks
- ret
- HITEST: in al,PORTC ;Read DIP switches
- and al,0FH
- cbw
- mov cx,ax ;Leave count of 32K banks in (cx)
- mov dx,1000H ;Assume we start just above Planar
- mov bx,0
- ret
- ;
- ; Video display routines
- ;
- CLEAR: mov ax,cs ;Make (ds)=(cs)
- mov ds,ax
- mov ax,0500H ;Set for Screen Page 0
- int 10H
- mov ah,0FH ;Find out screen size
- int 10H
- mov dl,ah ;Put away biggest column
- mov dh,25
- mov cx,0
- mov ax,0600H
- mov bh,2 ;Set normal attribute
- int 10H ;Clear screen
- mov bh,0 ;Select Screen Page 0
- mov dx,0 ;Set cursor to upper left corner
- mov ah,2
- int 10H
- mov CYCLES,0 ;Reset counters
- mov MINI,MAX
- DISPLAY MSG6
- mov si,offset MSG2
- ;
- ; TTYOUT assumes that (bh)=0 to select screen #0
- TTYOUT: mov al,[si] ;Get next byte
- inc si
- cmp al,0 ;Finished?
- je TTYXIT ;Yes.
- VIDEO
- jmp TTYOUT
- TTYXIT: ret
- ;
- ; NMI Substitute Routine
- ;
- NMISVC proc near
- push ax
- in al,PORTC
- test al,40H ;Parity 2?
- jz exit
- mov al,0
- out 0A0H,al ;disable NMI
- in al,PORTB
- or al,20H ;Disable IO CK ENABLE so we can
- out PORTB,al ; strobe it to clear parity check
- and al,not 20h ;Now, take it away again
- out PORTB,al
- mov al,80H
- out 0A0H,al ;Reenable NMI
- mov cs:FLAG,al ;Set the FLAG to note the error
- EXIT: pop ax
- iret
- NMISVC endp
- ;
- TEST ends
- ;
- SPAREA segment stack
- dw 256 dup (0)
- SPAREA ends
- end INIT